#include "../src/UILoader.hpp"
#include "../src/PoseGL.hpp"
#include "../src/DataReader.hpp"
#include "../src/mkvPlayer.hpp"
#include "../src/mpegPlayer.hpp"
#include "../src/FileScan.hpp"
#include "../src/dbusClient.hpp"
#include "../src/PlayFinishException.hpp"
#include <thread>
#include <chrono>
#include <array>
#include <string>
#include <filesystem>
#include <stdexcept>
#include <fmt/format.h>
#include <spdlog/spdlog.h>
#include <atomic>
using namespace std::chrono_literals;

PoseGL* poseGL=nullptr;
UILoader* ui=nullptr;
dbusClient interface;

std::string currentPath;

class GlobalPlayer
{
  public:
    GlobalPlayer(const std::vector<std::string> & UUIDList_)
    : UUIDList(UUIDList_)
    {
      originalVideo.reserve(UUIDList.size());
      for(int i=0;i<UUIDList.size();i++)
        originalVideo.emplace_back(new MKVPlayer());
    }
    virtual ~GlobalPlayer()
    {}
    void Start(std::filesystem::path dir)
    {
      reader.RefreshData(dir/"output_3d.txt");
      SMPLplayer.Start(dir/"smpl_vis.mp4",false);
      for(int i=0;i<UUIDList.size();i++)
        originalVideo[i]->Start(dir/fmt::format("{}.mkv",UUIDList[i]),false);
      PlayStatus=true;

      //启动时钟
      clockThread=std::jthread([this](std::stop_token token){
        while(!token.stop_requested())
        {
          std::this_thread::sleep_for(0.1s);
          try
          {
            Timeout();
          }
          catch(const PlayFinishException& e)
          {
            break;
          }
        }
      });
    }
    void Stop()
    {
      SMPLplayer.Stop();
      for(int i=0;i<UUIDList.size();i++)
        originalVideo[i]->Stop();
      PlayStatus=false;
      ui->SwitchButtonToStop();

      if(clockThread.joinable())
      {
        clockThread.request_stop();
        clockThread.join();
      }
    }
    void Continue()
    {
      pauseFlag=false;
    }
    void Pause()
    {
      pauseFlag=true;
    }

    bool GetPauseStatus()
    {
      return pauseFlag;
    }
    bool GetStatus()
    {
      return PlayStatus;
    }
  private:
    std::atomic_bool PlayStatus=false;

    //播放对象
    std::vector<std::unique_ptr<MKVPlayer>> originalVideo;
    MPEGPlayer SMPLplayer;
    DataReader reader;
    std::vector<std::string> UUIDList;
    //缓存
    std::array<Cood3D,25> poseList;
    //ClockPause
    std::atomic_bool pauseFlag=false;
    //Clock
    std::jthread clockThread;

    void Timeout()
    //处理一帧
    {
      if(pauseFlag) return;
      for(int i=0;i<originalVideo.size();i++)
      {
        char* ImageData=new char[1920*1080*3];
        originalVideo[i]->GetNewImage(ImageData);
        ui->DisplayCamera(ImageData,1920,1080,i);
      }
      {
        char* ImageData=new char[1920*1080*3];
        SMPLplayer.GetNewImage(ImageData);
        ui->DisplaySMPL(ImageData,1920,1080);
      }
      {
        reader>>poseList;
        ui->DisplayCoord(poseList);
        poseGL->ShowPose(poseList);
      }
      ui->RefreshUI();
    }
};
std::unique_ptr<GlobalPlayer> player;


void Pose3D_Init(int width,int height)
{
  poseGL->Init(width,height);
}

void Pose3D_Display()
{
  poseGL->Display();
}

void Pose3D_Resize(int width,int height)
{
  poseGL->Resize(width,height);
}


bool Handle_PlayControl()
{
  //todo
  if(player->GetStatus())
  {
    player->Stop();
    return false;
  }
  else
  {
    if(currentPath.length()==0) return false;
    player->Start(currentPath);
    return true;
  }
}

void Handle_RecordChange(std::string path)
{
  currentPath=path;
}

void Handle_Output(long recid,std::string path)
{
  if(std::filesystem::exists(path))
    interface.OutputData(recid,path);
}

std::vector<std::tuple<long,std::string,std::string>> Handle_GetRecordList(long id)
{
  std::vector<std::tuple<long,std::string,std::string>> res;
  auto list=interface.GetHandleFinishTaskList(id);
  res.reserve(list.size());
  for(const long & i : list)
    res.push_back(interface.GetRecordInf(i));
  return res;
}

bool Handle_PauseControl()
{
  if(player->GetPauseStatus())
    player->Continue();
  else
    player->Pause();
  return player->GetPauseStatus();
}

int main()
{
  gst_init(nullptr,nullptr);
  {//Init
    auto cameraidlist=interface.GetCameraIDList();
    player.reset(new GlobalPlayer(cameraidlist));
    poseGL=new PoseGL();
  }

  auto app=Gtk::Application::create("org.ReviewUI.test"); UILoader loader;
  ui=&loader;
  ui->funcInitPose3D=Pose3D_Init;
  ui->funcDisplayPose3D=Pose3D_Display;
  ui->funcResizePose3D=Pose3D_Resize;
  ui->funcPlayStatusControl=Handle_PlayControl;
  ui->funcGetRecordList=Handle_GetRecordList;
  ui->funcSetRecordChange=Handle_RecordChange;
  ui->funcPauseControl=Handle_PauseControl;
  ui->funcOutput=Handle_Output;

  //首次加载录制列表
  {
    std::vector<long> task_list=interface.GetAllTaskList();
    std::vector<std::tuple<long,std::string,std::string>> show_task_list;
    show_task_list.reserve(task_list.size());
    for(const long & i : task_list)
    {
      auto inf=interface.GetTaskInf(i);
      show_task_list.push_back(std::make_tuple(
        i,
        std::get<0>(inf),
        std::get<1>(inf)
      ));
    }
    ui->SetTaskList(show_task_list);
  }
  
  loader.app_show(app);
  if(player->GetStatus())
    player->Stop();
}
